<?php

namespace common\service;

use common\model\EntityModel;
use common\model\ProjectModel;
use common\model\StatusModel;
use support\EntityTaskFilterParser;
use think\Exception;
use support\ErrorCode;
use support\SingletonTrait;
use common\model\PlanModel;
use common\model\TaskModel;
use common\model\StepCategoryModel;
use common\exception\LogicException;
use common\model\AttributeValueModel;
use common\model\ProjectCapacityReportDailyModel;

class ProjectCapacityReportDailyService
{
    // 单例工具
    use SingletonTrait;

    use EntityTaskFilterParser;

    /**
     * 获取产能上报数据，可查询多个step_category_id
     * @param int $projectId
     * @param int|array $stepCategoryIdList
     * @param string $startTimestamp
     * @param string $endTimestamp
     * @return array|false|mixed|string
     */
    private function getByDateRange(int $projectId, $stepCategoryIdList, string $startTimestamp, string $endTimestamp)
    {
        if (!is_array($stepCategoryIdList)) {
            $stepCategoryIdList = [$stepCategoryIdList];
        }

        $filter = [
            'project_id' => $projectId,
            ['report_date' => ['EGT', $startTimestamp]],
            ['report_date' => ['ELT', $endTimestamp]],
            'step_category_id' => ['IN', $stepCategoryIdList]
        ];

        return model(ProjectCapacityReportDailyModel::class)
            ->where($filter)
            ->field("id, step_category_id, number, from_unixtime(report_date,'%Y-%m-%d') as report_date_str")
            ->order("report_date asc")
            ->select();
    }

    /**
     * 获取产能上报数据，格式化返回
     * @param $param
     * @return array
     */
    public function selectByStepCategory($param)
    {
        $projectId = $param['project_id'];
        $stepCategoryIdList = explode(",", $param['step_category_id_list']);
        $startTimestamp = $param['start_time'];
        $endTimestamp = $param['end_time'];

        $rows = self::getByDateRange($projectId, $stepCategoryIdList, $startTimestamp, $endTimestamp);
        $rows = array_combine(array_column($rows, 'report_date_str'), array_column($rows, 'number'));

        $res = [];
        while ($startTimestamp <= $endTimestamp) {
            $dateIterator = date("Y-m-d", $startTimestamp);
            $res[] = [
                'date' => $dateIterator,
                'number' => $rows[$dateIterator] ?? 0
            ];
            $startTimestamp += 60 * 60 * 24;
        }
        return $res;
    }

    /**保存当日产能上报数据
     * @param $param
     * @return bool
     * @throws \Exception
     */
    public function saveByStepCategory($param)
    {
        $projectId = $param['project_id'];
        $reportTime = $param['report_time'];

        if (is_array($param['step_category_id_list'])) {
            $stepCategoryIdList = $param['step_category_id_list'];
        } else {
            $stepCategoryIdList = explode(",", $param['step_category_id_list']);
        }

        $number = $param['number'];
        if (empty($number)) {
            $number = 0;
        }

        if (!is_array($stepCategoryIdList)) {
            $stepCategoryIdList = [$stepCategoryIdList];
        }

        // 20230323 需求变更 解除此限制
//        $monthRequired = self::getStatisticsByMonth($projectId, $stepCategoryIdList, date('Y-m', reportTime));
//        if($number > $monthRequired['statistics']['required']) {
//            throw new LogicException('Max require limitation exceeded!', ErrorCode::PROJECT_CAPACITY_LIMIT_EXCEED);
//        }

        $dateRange = get_current_day_range($reportTime);
        $recExist = self::getByDateRange($projectId, $stepCategoryIdList, $dateRange['sdate'], $dateRange['edate']);
        $recExist = array_combine(array_column($recExist, "step_category_id"), $recExist);

        $err = false;
        foreach ($stepCategoryIdList as $stepCategoryId) {
            if (in_array($stepCategoryId, array_keys($recExist))) {
                $update = [
                    'id' => $recExist[$stepCategoryId]['id'],
                    'number' => $number,
                    'updated_by' => fill_created_by(),
                    'updated' => time(),
                ];
                model(ProjectCapacityReportDailyModel::class)->save($update);
                $err |= false;
            } else {
                $create = [
                    'number' => $number,
                    'tenant_id' => auto_fill_tenant_id(),
                    'project_id' => $projectId,
                    'step_category_id' => $stepCategoryId,
                    'created_by' => fill_created_by(),
                    'created' => time(),
                    'report_date' => $dateRange['sdate'],
                ];
                model(ProjectCapacityReportDailyModel::class)->add($create);
                $err |= false;
            }
        }
        return !$err;
    }

    /**
     * 按月批量保存产能上报
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function saveByCapacityList($param)
    {
        $projectId = $param['project_id'];
        $stepCategoryIdList = explode(",", $param['step_category_id_list']);
        $yearMonth = $param['year_month'];
        $capacityList = $param['capacity_report_list'] ?? [];

        $res = [];

        // 过滤合法上报数据
        $lastDay = date('t', strtotime($yearMonth));
        $capacityList = array_values(array_filter($capacityList, function ($capacityItem) use ($lastDay) {
            if (!isset($capacityItem['report_time']) || !is_numeric($capacityItem['report_time'])) {
                return false;
            }
            if ($capacityItem['report_time'] < 0 || $capacityItem['report_time'] > $lastDay) {
                return false;
            }
            if (!isset($capacityItem['number']) || !is_numeric($capacityItem['number']) || $capacityItem['number'] < 0) {
                return false;
            }
            return true;
        }));

        // 20230323 需求变更 解除此限制
        // 计算在不需要更新的日期里，已经排产的总量
        // 得到剩余需要排产的总量，对比确认本次更新是否超出需求
//        $numberImported = array_sum(array_column($capacityList, 'number'));
//        $numberRequired = 0;
//        for($currentDay = 1; $currentDay <= $lastDay; $currentDay++){
//            $dayRequired = self::getStatisticsByDate($projectId, $stepCategoryIdList, "${yearMonth}-$currentDay");
//            $numberRequired += $dayRequired['statistics']['required'];
//            if($numberImported <= $numberRequired) {
//                break;
//            }
//        }
//        if($numberImported > $numberRequired) {
//            throw new LogicException('Max require limitation exceeded!', ErrorCode::PROJECT_CAPACITY_LIMIT_EXCEED);
//        }

        foreach ($capacityList as $capacityItem) {
            $date = $yearMonth . '-' . $capacityItem['report_time'];
            $dateTimeStamp = strtotime($date);
            $number = empty($capacityItem['number']) ? 0 : $capacityItem['number'];
            $res[] = [
                'date' => $date,
                'status' => self::saveByStepCategory([
                    'project_id' => $projectId,
                    'report_time' => $dateTimeStamp,
                    'step_category_id_list' => $stepCategoryIdList,
                    'number' => $number
                ])
            ];
        }
        return $res;
    }

    /**
     * 按日获取统计
     * @param $param
     * @return array
     */
    public function getStatisticsByRange($param)
    {
        $projectId = $param['project_id'];
        $stepCategoryIdList = explode(",", $param['step_category_id_list']);
        $startTimestamp = $param['start_time'];
        $endTimestamp = $param['end_time'];

        return [
            'date_range' => [
                'start' => date('Y-m-d H:i:s', $startTimestamp),
                'end' => date('Y-m-d H:i:s', $endTimestamp),
            ],
            'statistics' => self::getStatistics($projectId, $stepCategoryIdList, $startTimestamp, $endTimestamp)
        ];
    }

    /**
     * 按月获取统计
     * @param $param
     * @return array
     */
    public function getStatisticsByMonth($param)
    {
        $projectId = $param['project_id'];
        $stepCategoryIdList = explode(",", $param['step_category_id_list']);
        $yearMonth = $param['year_month'];

        $dateRange = get_month_time($yearMonth);
        $startTimestamp = $dateRange['sdate'];
        $endTimestamp = $dateRange['edate'];
        return [
            'date_range' => [
                'start' => date('Y-m-d H:i:s', $startTimestamp),
                'end' => date('Y-m-d H:i:s', $endTimestamp),
            ],
            'statistics' => self::getStatistics($projectId, $stepCategoryIdList, $startTimestamp, $endTimestamp)
        ];
    }

    /**
     * 按时段获取统计
     * @param int $projectId
     * @param $stepCategoryIdList
     * @param string $startTimestamp
     * @param string $endTimestamp
     * @return array
     */
    private function getStatistics(int $projectId, $stepCategoryIdList, string $startTimestamp, string $endTimestamp)
    {
        $reportedNum = self::getReported($projectId, $stepCategoryIdList, $startTimestamp, $endTimestamp);

        $needDuration = in_array(41, $stepCategoryIdList);      //? 41
        $claimedDetail = self::getClaimed($projectId, $stepCategoryIdList, $startTimestamp, $endTimestamp, $needDuration);

        return [
            'claimed_episode' => $claimedDetail['episode'],
            'claimed' => $claimedDetail['number'],
            'reported' => $reportedNum,
//            'required' => $claimedDetail['number'] > $reportedNum ? $claimedDetail['number'] - $reportedNum : 0
        ];
    }

    /**
     * 获取时间范围内产能上报数据
     * @param int $projectId
     * @param int|array $stepCategoryIdList
     * @param string $startTimestamp
     * @param string $endTimestamp
     * @return int|mixed
     */
    private function getReported(int $projectId, $stepCategoryIdList, string $startTimestamp, string $endTimestamp)
    {
        $plannedRecord = self::getByDateRange($projectId, $stepCategoryIdList, $startTimestamp, $endTimestamp);
        $plannedRecord = array_combine(array_column($plannedRecord, 'report_date_str'), $plannedRecord);

        $result = 0;
        foreach (array_column($plannedRecord, "number") as $num) {
            $result += $num;
        }
        return $result;
    }

    /**
     * 获取时间范围内所需产能
     * @param int $projectId
     * @param int|array $stepCategoryIdList
     * @param string $startTimestamp
     * @param string $endTimestamp
     * @param bool $needDuration
     * @return int|mixed
     */
    private function getClaimed(int $projectId, $stepCategoryIdList, string $startTimestamp, string $endTimestamp, bool $needDuration = false)
    {
        if (!is_array($stepCategoryIdList)) {
            $stepCategoryIdList = [$stepCategoryIdList];
        }

        $statusService = StatusService::getInstance();
        $statusTaskClosed = $statusService->getTaskDefaultClosedStatus();

        // 查询指定交付时间范围内，相关的剧集、环节
        $planTaskRelation = model(PlanModel::class)
            ->join("task_relation_tag tr ON plan.task_id = tr.task_id", "LEFT")
            ->where([
                'plan.project_id' => 22,
                'plan.scope' => 'single',
                ['plan.end_time' => ['EGT', $startTimestamp]],
                ['plan.end_time' => ['ELT', $endTimestamp]],
                'tr.link_id' => ['IN', $stepCategoryIdList],
                'tr.link_module_code' => ['IN', ['show_step_category', 'step_category']]
            ])
            ->field(['plan.entity_id episode_id', 'tr.link_id step_category_id, plan.end_time plan_end_time'])
            ->select();

        $episodeList = [];
        foreach ($planTaskRelation as $item) {
            $episodeList[$item['episode_id']]['plan_end_time'] = $item['plan_end_time'];
            $episodeList[$item['episode_id']]['step_category_id_list'][] = $item['step_category_id'];
        }

        if (!empty($episodeList)) {
            $episodeFilter = [
                '_logic' => 'OR',
            ];
            foreach ($episodeList as $episodeId => $episodeItem) {
                $episodeFilter[] = [
                    'episode_id' => $episodeId,
                    'step_category_id' => ['IN', $episodeItem['step_category_id_list']],
                    'end_time' => ['ELT', $episodeItem['plan_end_time']]
                ];
            }

            if (!$needDuration) {
                // 仅获取任务数量
                $monthClaimedTotal = model(TaskModel::class)
                    ->where([
                        'project_id' => $projectId,
                        "json->>'$.task_status' <> ${statusTaskClosed['id']}",
                        $episodeFilter
                    ])
                    ->field("count( distinct entity_id) need_num")
                    ->find()['need_num'];
            } else {
                // 获取任务实体 - 镜头 - 镜头预估时长
                $shotTaskList = model(TaskModel::class)
                    ->where([
                        'project_id' => $projectId,
                        "json->>'$.task_status' <> ${statusTaskClosed['id']}",
                        $episodeFilter
                    ])
                    ->field("distinct task.entity_id shot_entity_id")
                    ->select();
                if (!empty($shotTaskList)) {
                    $durationList = model(EntityModel::class)
                        ->where([
                            'id' => ['IN', array_column($shotTaskList, 'shot_entity_id')]
                        ])
                        ->field('json->>\'$.shot_estimate_duration\' as shot_estimate_duration')
                        ->select();

                    $monthClaimedTotal = 0;
                    foreach ($durationList as $durationItem) {
                        if (is_numeric($durationItem['shot_estimate_duration'])) {
                            $monthClaimedTotal += $durationItem['shot_estimate_duration'];
                        }
                    }
                }
            }
        }

        return [
            'episode' => count($episodeList),
            'number' => $monthClaimedTotal ?? 0
        ];
    }
}
